/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dk.rofl.units;

import dk.rofl.graphics.GameTileSet;
import dk.rofl.items.Armor;
import dk.rofl.items.Weapon;
import java.awt.Point;
import java.awt.image.BufferedImage;
import rofl.Utils;

/**
 *
 * @author menderleit
 */
public abstract class GameUnit {

    public static final int IMG_NORMAL = 0;
    public static final int IMG_DEAD = 1;
    private int level;
    private int baseStamina;
    private int baseStrength;
    private int currentHealth;
    private boolean tryToParry;
    private boolean parried;
    private boolean riposte;
    private Point position;
    private Armor[] armor;
    private Weapon weapon;
    private GameTileSet gts;

    // Constructor
    public GameUnit(GameTileSet gts, int level) {
        this.gts = gts;
        this.level = level;
        tryToParry = false;
        parried = false;
        riposte = false;
        armor = new Armor[5];
    }

    public void tryToParry() {
        tryToParry = true;
    }

    public void clearTryToParry() {
        tryToParry = false;
    }
    
    public boolean getTryToParry() {
        return tryToParry;
    }

    public void setParried(boolean parry) {
        parried = parry;
    }
    
    public boolean getParried() {
        return parried;
    }
    
    public boolean getRiposte() {
        return riposte;
    }
    
    // Attack an enemy.
    public DamageReport attack(GameUnit enemy) {
        int finalDmg = 0;

        // Base attack damage
        int baseDmg = Utils.rnd().nextInt(getStrength()) + getStrength();
        finalDmg += baseDmg;

        // Add weapon damage
        int weaponDmg = Utils.rnd().nextInt(weapon.getMaxDamage() - weapon.getMinDamage()) + weapon.getMinDamage();
        finalDmg += weaponDmg;

        // Critical strike chance
        int levelDif = enemy.getLevel() - level;
        boolean wasCrit = UnitUtils.tryCrit(levelDif);
        if (wasCrit) {
            finalDmg = finalDmg * 2;
        }

        enemy.setParried(false);
        if (enemy.getTryToParry()) {
            enemy.clearTryToParry();
            enemy.setParried(UnitUtils.tryParry(levelDif));
        }

        // Do the damage.
        int dmgDone = enemy.takeDamage(finalDmg);

        // Create a damage report and return it.
        DamageReport dr = new DamageReport(baseDmg, weaponDmg, dmgDone, wasCrit, enemy.getParried(), enemy.getRiposte());
        return dr;
    }

    // Take damage from an attack.
    public int takeDamage(int attackDmg) {
        int dmg = attackDmg - getArmorRating();
        if (dmg < (int) ((double) attackDmg * 0.25)) {
            dmg = (int) ((double) attackDmg * 0.25);
        }

        riposte = false;
        if (!parried) {
            currentHealth -= dmg;
        } else {
            int r = Utils.rnd().nextInt(100);
            if(r < 25) {
                riposte = true;
            }
        }

        return dmg;
    }

    // Set the base stamina of this unit.
    protected void setBaseStamina(int stamina) {
        baseStamina = stamina;
    }

    // Get the base stamina of this unit.
    protected int getBaseStamina() {
        return baseStamina;
    }

    // Add an amount to the base stamina of this unit.
    protected void addBaseStamina(int amount) {
        baseStamina += amount;
    }

    // Get the total stamina of this unit.
    public int getStamina() {
        int sta = baseStamina;
        for (int i = 0; i < armor.length; i++) {
            if (armor[i] != null) {
                sta += armor[i].getStaminaBonus();
            }
        }
        if (weapon != null) {
            sta += weapon.getStaminaBonus();
        }
        return sta;
    }

    // Set the base strength of this unit.
    protected void setBaseStrength(int strength) {
        baseStrength = strength;
    }

    // Add an amount to the base strength of this unit.
    protected void addBaseStrength(int amount) {
        baseStrength += amount;
    }

    // Get the base stamina of this unit.
    protected int getBaseStrength() {
        return baseStrength;
    }

    // Get the total strength of this unit.
    public int getStrength() {
        int str = baseStrength;
        for (int i = 0; i < armor.length; i++) {
            if (armor[i] != null) {
                str += armor[i].getStrengthBonus();
            }
        }
        if (weapon != null) {
            str += weapon.getStrengthBonus();
        }
        return str;
    }

    // Get the max health of this unit.
    public int getMaxHealth() {
        int hp = getStamina() * UnitUtils.staminaValue;
        return hp;
    }

    // Set the current health of this unit.
    public void setCurrentHealth(int currentHealth) {
        this.currentHealth = currentHealth;
        getCurrentHealth();
    }

    public void addHealth(int health) {
        currentHealth += health;
        getCurrentHealth();
    }

    // Get the current health of this unit.
    public int getCurrentHealth() {
        if (currentHealth > getMaxHealth()) {
            currentHealth = getMaxHealth();
        }
        if (currentHealth <= 0) {
            currentHealth = 0;
        }
        return currentHealth;
    }

    // Is this unit dead?
    public boolean isDead() {
        boolean dead = false;
        if (currentHealth <= 0) {
            currentHealth = 0;
            dead = true;
        }
        return dead;
    }

    public void setArmorSlot(int slot, Armor a) {
        armor[slot] = a;
    }

    public Armor getArmorSlot(int slot) {
        return armor[slot];
    }

    // Get the armor list of this unit.
    public Armor[] getArmor() {
        return armor;
    }

    // Get the total armor rating of this unit.
    public int getArmorRating() {
        int ar = 0;
        for (int i = 0; i < armor.length; i++) {
            ar += armor[i].getArmorRating();
        }
        return ar;
    }

    // Set the weapon of this unit.
    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }

    // Get the weapon of this unit.
    public Weapon getWeapon() {
        return weapon;
    }

    public void nextLevel() {
        level++;
    }

    // Get the level of this unit.
    public int getLevel() {
        return level;
    }

    // Set the position of this unit.
    public void setPosition(Point p) {
        position = p;
    }

    // Set the position of this unit.
    public void setPosition(int x, int y) {
        position = new Point(x, y);
    }

    // Get the position of this unit.
    public Point getPosition() {
        return position;
    }

    // Get the X-position of this unit.
    public int getXPosition() {
        return position.x;
    }

    // Get the Y-position of this unit.
    public int getYPosition() {
        return position.y;
    }

    // Move this unit 1 tile up.
    public void moveUp() {
        position = new Point(position.x, position.y - 1);
    }

    // Move this unit 1 tile down.
    public void moveDown() {
        position = new Point(position.x, position.y + 1);
    }

    // Move this unit 1 tile left.
    public void moveLeft() {
        position = new Point(position.x - 1, position.y);
    }

    // Move this unit 1 tile right.
    public void moveRight() {
        position = new Point(position.x + 1, position.y);
    }

    public BufferedImage getImage() {
        BufferedImage img;
        if (isDead()) {
            img = gts.getTileImage(IMG_NORMAL);
        } else {
            img = gts.getTileImage(IMG_NORMAL);
        }
        return img;
    }

    public void setArmor(Armor[] armor) {
        this.armor = armor;
    }

    public void setLevel(int level) {
        this.level = level;
    }   
}
